#include "../inc/server.h"
#include "../inc/forecast.h"

pthread_mutex_t mutex; // 互斥锁

PSI Server_Init(int ser_port) // 服务器初始化
{
    // 申请结构体堆空间，存放服务器套接字，端口号等信息
    PSI ser_info_struct = (PSI)malloc(sizeof(SI));
    if (ser_info_struct == (PSI)NULL)
    {
        perror("malloc");
        return (PSI)-1;
    }
    // 清空堆内存
    memset(ser_info_struct, 0, sizeof(SI));
    // 创建套接字
    if ((ser_info_struct->ser_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket");
        return (PSI)-1;
    }
    // 初始化服务器地址结构体
    struct sockaddr_in tcp_ser_info;
    memset(&tcp_ser_info, 0, sizeof(struct sockaddr_in));

    tcp_ser_info.sin_family = AF_INET;
    tcp_ser_info.sin_port = htons(ser_port);
    tcp_ser_info.sin_addr.s_addr = htonl(INADDR_ANY);

    // 绑定
    if (bind(ser_info_struct->ser_fd, (struct sockaddr *)&tcp_ser_info, sizeof(struct sockaddr_in)) == -1)
    {
        perror("bind");
        close(ser_info_struct->ser_fd);
        exit(EXIT_FAILURE);
    }
    // 监听 设置客户端等待连接个数
    if (listen(ser_info_struct->ser_fd, MAX_WAIT) == -1)
    {
        perror("listen");
        close(ser_info_struct->ser_fd);
        exit(EXIT_FAILURE);
    }

    // 创建在线客户端链表头结点的堆空间
    if ((ser_info_struct->cli_node_head = Create_Cnode()) == (PCN)-1)
    {
        perror("Create_Cnode");
        return (PSI)-1;
    }

    // 初始化互斥锁
    if (pthread_mutex_init(&ser_info_struct->mutex, NULL) != 0)
    {
        perror("pthread_mutex_init");
        return (PSI)-1;
    }
    // 创建线程专门等待客户端连接
    if (pthread_create(&ser_info_struct->wait_cli_tid, NULL, Wait_For_Client_Connect, (void *)ser_info_struct) != 0)
    {
        perror("pthread_create");
        return (PSI)-1;
    }
    return ser_info_struct;
}

// 创建客户端节点
PCN Create_Cnode()
{
    PCN new_cnode = (PCN)malloc(sizeof(CN));
    if (new_cnode == (PCN)NULL)
    {
        perror("malloc");
        return (PCN)-1;
    }
    // 清空堆内存
    memset(new_cnode, 0, sizeof(CN));
    new_cnode->next = new_cnode;
    new_cnode->prev = new_cnode;
    return new_cnode;
}

// 在客户端链表尾部添加新节点
bool Cnode_Add_Tail(PCN cli_head, PCN new_cnode)
{
    if (cli_head == (PCN)NULL || new_cnode == (PCN)NULL)
    {
        printf("节点异常！\n");
        return false;
    }
    // 将新节点添加到链表尾部
    new_cnode->prev = cli_head->prev;
    cli_head->prev->next = new_cnode;
    new_cnode->next = cli_head;
    cli_head->prev = new_cnode;
    return true;
}

// 删除客户端节点
bool Del_Client_Node(PCN del_cnode)
{
    if (del_cnode == (PCN)NULL)
    {
        printf("删除的节点为空！\n");
        return false;
    }
    del_cnode->prev->next = del_cnode->next;
    del_cnode->next->prev = del_cnode->prev;
    del_cnode->prev = NULL;
    del_cnode->next = NULL;
    free(del_cnode);
    return true;
}

// 创建等待客户端连接的线程  arg存放了服务器信息结构体指针
void *Wait_For_Client_Connect(void *arg)
{
    printf("等待客户端连接...\n");
    PSI ser_info_struct = (PSI)arg;
    struct sockaddr_in cli_info;
    int addr_len = sizeof(cli_info);
    while (1)
    {
        // 清空客户端信息结构体
        memset(&cli_info, 0, addr_len);
        int cli_fd = accept(ser_info_struct->ser_fd, (struct sockaddr *)&cli_info, &addr_len);
        if (cli_fd == -1)
        {
            perror("accept");
            pthread_exit((void *)-1);
        }
        printf("客户端 %s 连接成功！\n", inet_ntoa(cli_info.sin_addr));

        // 创建新的客户端节点
        PCN new_cnode = Create_Cnode();
        if (new_cnode == (PCN)NULL)
        {
            perror("创建客户端节点失败！\n");
            pthread_exit((void *)-1);
        }
        // 把当前链接过来的客户端的套接字、ip、存放到节点中
        new_cnode->cli_fd = cli_fd;
        strcpy(new_cnode->cli_ip, inet_ntoa(cli_info.sin_addr));
        new_cnode->ser_info = ser_info_struct;
        // 上锁
        pthread_mutex_lock(&ser_info_struct->mutex);
        // 把新创建的节点尾插到客户端链表中
        Cnode_Add_Tail(ser_info_struct->cli_node_head, new_cnode);
        // 解锁
        pthread_mutex_unlock(&ser_info_struct->mutex);
        // 阻塞线程
        if (pthread_create(&new_cnode->cli_tid, NULL, Mode_Select, (void *)new_cnode) != 0)
        {
            perror("创建线程失败！\n");
            pthread_exit((void *)-1);
        }
    }
    pthread_exit((void *)0);
}



bool Function_Select(PSI server_info)
{
    // 显示功能菜单

    int select_num;
    while (1)
    {
        sleep(3);
        system("clear");
        printf("🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧\n");
        printf("🐧🐧🐧🐧🐧🐧🐧🐧     Penguin_Chat   🐧🐧🐧🐧🐧🐧🐧🐧\n");
        printf("🐧🐧🐧🐧🐧🐧🐧🐧    (1)显示在线客户 🐧🐧🐧🐧🐧🐧🐧🐧\n");
        printf("🐧🐧🐧🐧🐧🐧🐧🐧    (2)关闭服务器   🐧🐧🐧🐧🐧🐧🐧🐧\n");
        printf("🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧🐧\n");

        printf("请输入你的选择：");
        scanf("%d", &select_num);

        switch (select_num)
        {
        case 1:
            system("clear");
            Show_Online_Client_UI(Show_Online_Client(server_info));
            break;
        case 2:
            goto exit;
            break;

        default:
            printf("指令有误！\n");
            break;
        }
    }

exit:
    
    return true;
}

bool Send_Message_To_Client(int cli_fd, const char *message)
{
    ssize_t send_len = send(cli_fd, message, strlen(message), 0);
    if (send_len == -1)
    {
        perror("send");
        return false;
    }
    else if (send_len == 0)
    {
        printf("客户端已关闭连接\n");
        return false;
    }
    else
    {
        printf("消息发送成功\n");
        return true;
    }
}

PCN Find_Client_Node(PCN cnode, char *target_ip)
{
    PCN chead = cnode->ser_info->cli_node_head;
    pthread_mutex_lock(&(cnode->ser_info->mutex));
    for (PCN tmp_client_node = chead->next;
         tmp_client_node != chead;
         tmp_client_node = tmp_client_node->next)
    {
        if (strcmp(tmp_client_node->cli_ip, target_ip) == 0)
        {
            pthread_mutex_unlock(&(cnode->ser_info->mutex));
            printf("找到客户端节点\n");
            return tmp_client_node;
        }
    }
    pthread_mutex_unlock(&(cnode->ser_info->mutex));
    return NULL;
}

void *Mode_Select(void *arg) // 客户端连接成功之后，对应的线程进入功能选择应答选择函数
{
    // 设置线程自己为分离属性
    pthread_detach(pthread_self());
    char target_ip[IP_LEN]; // 目标客户端ip
    char city[50]; // 目标城市
    char package[MSG_MAX_LEN]; // 消息包
    PCN cnode = (PCN)arg;
    // 该函数是客户端连接成功之后客户端线程立马进来的函数
    // 专门给客户端进行功能选择的函数接口
    char msg[MSG_MAX_LEN];
loop:
    while (1)
    {
        memset(msg, 0, MSG_MAX_LEN);
        printf("请选择功能：\n");
        int read_ret = read(cnode->cli_fd, msg, MSG_MAX_LEN); // 读客户端的功能选择
        printf("客户端发送的消息%s\n", msg);
        printf("=============================================\n");
        if (read_ret == -1)
        {
            perror("read ...");
            pthread_exit((void *)-1);
        }
        else if (read_ret == 0)
        {
            printf("%s下线！111\n", cnode->cli_ip);
            // 当前客户端掉线了
            // 上锁
            pthread_mutex_lock(&(cnode->ser_info->mutex));

            if (Del_Client_Node(cnode) == false)
            {
                printf("删除下线客户端结点失败！\n");
                // 解锁
                pthread_mutex_unlock(&(cnode->ser_info->mutex));
                pthread_exit((void *)-1); // 线程退出
            }
            // 解锁
            pthread_mutex_unlock(&(cnode->ser_info->mutex));
            goto loop;
            free(cnode); // 释放当前客户端结点堆空间
            break;
        }
        else
        {
            if (strcmp(PRIVATE_CHAT, msg + 14) == 0) // 私聊=====================================================
            {
                printf("客户端：%s要私聊！\n", cnode->cli_ip);
                strncpy(target_ip, msg, 14);

                PCN tnode = Find_Client_Node(cnode, target_ip);
                if (tnode == NULL)
                {
                    printf("客户端：%s要私聊的客户端不存在！\n", cnode->cli_ip);
                }
                Private_Task(cnode, target_ip); // 私聊任务
            }
            else if (strcmp(WE_CHAT, msg) == 0) // 群聊======================================================
            {

                printf("客户端：%s要群聊！\n", cnode->cli_ip);
                Broadcast_Task(cnode);
            }
            else if (strcmp(SHOW_WEATHER, msg) == 0) // 显示天气==========================================================
            {
                printf("客户端%s要显示天气\n", cnode->cli_ip);
                //接收来自客户端要查询的城市
                read(cnode->cli_fd, city, 50);
                printf("客户端%s要查询的城市是%s\n", cnode->cli_ip, city);
                //调用天气查询函数
                strcpy(package, Get_Weather(city));
                memset(city, 0, 50);
                printf("查询到的天气信息是：%s\n", package);
                //将天气信息发送给客户端
                write(cnode->cli_fd, package, strlen(package));
                printf("天气信息发送成功！\n");
                memset(package, 0, 1024);
                goto loop;
            }
            else if (strcmp(SHOW_ONLINE_CLI, msg) == 0) // 显示在线人员===========================================================
            {
                printf("客户端%s要显示在线人员\n", cnode->cli_ip);
                printf("在线人员有：\n%s\n",Show_Online_Client(cnode->ser_info));
                write(cnode->cli_fd, Show_Online_Client(cnode->ser_info), strlen(Show_Online_Client(cnode->ser_info)));
                goto loop;
            }
            else if (strcmp(EXIT_MASK, msg) == 0) // 退出============================================================
            {
                printf("客户端%s要退出！\n", cnode->cli_ip);
            }
            else // 网络传输有误=============================================================
            {
                printf("网络传输有误!\n");
            }
        }
    }
    pthread_exit((void *)0);
}



// bool Tcp_Broadcast_Free(PSI broadcast_inf_struct)
// {

//     if (shutdown(broadcast_inf_struct->ser_fd, SHUT_RDWR) == -1)
//     {
//         perror("shutdown ...");
//         return false;
//     }

//     // 广播给每一个客户端服务器要退出了
//     if (Send_All(broadcast_inf_struct->cli_node_head, EXIT_MASK, SEND_MODE_EXIT) == false)
//     {
//         printf("发送广播消息失败！\n");
//         return false;
//     }

//     while (1)
//     {
//         if (broadcast_inf_struct->cli_node_head->next == broadcast_inf_struct->cli_node_head)
//         {
//             free(broadcast_inf_struct->cli_node_head);
//             break;
//         }
//         printf("等待客户端退出！\n");
//         sleep(1);
//     }

//     pthread_join(broadcast_inf_struct->wait_cli_tid, (void *)NULL);

//     if (close(broadcast_inf_struct->ser_fd) == -1)
//     {
//         perror("close ...");
//         return false;
//     }

//     if (pthread_mutex_destroy(&(broadcast_inf_struct->mutex)) != 0)
//     {
//         perror("pthread_mutex_destroy ...");
//         return false;
//     }

//     free(broadcast_inf_struct);
//     return true;
// }